package hash;

import structure.Board;
import structure.Coordinate;
import structure.Move;

public class Hasher {
	
	private static Hasher instance;
	
	final long[][][] bitStrings;
	
	public static Hasher register(long[][][] bitStrings){
		if(instance != null)
			throw new RuntimeException("Hasher already registred");
		instance = new Hasher(bitStrings);
		return instance;
	}
	

	/*
	 * (rotate)Zp(z) =z2, z3, z4, z1, z6, z7, z8, z5
	 * (mirror)Zu(z) =z4, z3, z2, z1, z8, z7, z6, z5
	 * (color) Zk(z) =z5, z6, z7, z8, z1, z2, z3, z4.
	 */
	final static byte[] rotateShift = new byte[]{1,2,3,0,5,6,7,4};
	final static byte[] mirrrorShift = new byte[]{3,2,1,0,7,6,5,4};
	final static byte[] colorShift = new byte[]{4,5,6,7,0,1,2,3};
	
	public static Hasher getInstance(){
		if(instance == null)
			throw new RuntimeException("Hasher not registred");
		return instance;
	}
	
	private Hasher(long[][][] bitStrings){
		this.bitStrings = bitStrings;
	}
	
	
	public long getBitString(Coordinate where, byte color) {
		return bitStrings[where.x][where.y][(color+1)/2];
	}
	
	private long shiftByte(final long toShift, final byte from, final byte to){
		return ((toShift&((0xFF)<<(8*from)))>>(8*from))<<(8*to);
	}
	
	private long getShiftedHash(Long bitString, byte[] indices){
		long value  = bitString.longValue();
		long result = 0;
		for(byte i = 0; i<indices.length; i++)
			result = result | shiftByte(value,i,indices[i]);
		
		return result;
	}
	
	/**
	 * Return the mirrored hash
	 * @param bitString The original hash 
	 * @return The mirrored hash
	 */
	public long getMirroredHash(long bitString) {
		return getShiftedHash(bitString, mirrrorShift);
	}
	
	/**
	 * Return the rotated hash n times
	 * @param bitString The original hash 
	 * @param n The number of rotation 
	 * @return The hash after n rotation
	 */
	public long getRotatedHash(long bitString, byte n) {
		for(int i = 0; i<n;i++)
			bitString = getShiftedHash(bitString,rotateShift);
		
		return bitString;
	}
	
	/**
	 * Return the hash after inversion of the color
	 * @param bitString The original hash 
	 * @return The mirrored hash
	 */
	public long getInvereColorHash(long bitString) {
		return getShiftedHash(bitString, colorShift);
	}
	
	
	public boolean equals(long a, long b) {
		return a==b;
	}
	
	public long hash(Board board, Move move){
		return 0;
	}
}
